package secondary.employmentlaw;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import jade.content.Concept;
import jade.content.ContentElement;
import jade.content.lang.Codec;
import jade.content.lang.Codec.CodecException;
import jade.content.lang.sl.SLCodec;
import jade.content.onto.Ontology;
import jade.content.onto.OntologyException;
import jade.content.onto.UngroundedException;
import jade.content.onto.basic.Action;
import jade.core.behaviours.CyclicBehaviour;
import jade.lang.acl.ACLMessage;
import jade.util.leap.ArrayList;
import jade.util.leap.HashMap;
import jade.util.leap.Iterator;
import jade.util.leap.List;
import ontology.EmploymentLawOntology;
import ontology.UMCourtLOntology;
import ontology.actions.general.AddNewResult;
import ontology.actions.general.AddNewTime;
import ontology.actions.general.GetCase;
import ontology.actions.general.GetCases;
import ontology.actions.general.Index;
import ontology.actions.general.InformCase;
import ontology.actions.general.Log;
import ontology.actions.general.ReturnList;
import ontology.concepts.employmentlaw.Case;
import ontology.concepts.employmentlaw.Norm;
import ontology.concepts.general.Result;
import secondary.employmentlaw.DatabaseL.receiveBehaviour;
import classes.UMCourtAgent;
import ontology.UMCourtLVocabulary;

public class EvaluatorL extends UMCourtAgent 
{
	private Codec codec = new SLCodec();
	private Ontology ontology = EmploymentLawOntology.getInstance();
	private static Connection C;
	private static Statement Stmt;
	
	protected void setup() 
	{
		System.out.println(getDate()+ ": "+this.getLocalName()+" agent is now running...");
		registerAgent((String)getArguments()[0]);
		
		// Register language and ontology
	    getContentManager().registerLanguage(codec);
	    getContentManager().registerOntology(ontology);
		
		C = connectDB();
		System.out.println(getDate()+" : Connected to Database");
		
		//printStats();
		
		this.addBehaviour(new receiveBehaviour());
	}
	
	class receiveBehaviour extends CyclicBehaviour
	{
		@Override
		public void action() 
		{
			ACLMessage msg = receive();
	        if (msg == null) 
	        { 
	        	block(); 
	        	return; 
	        }
	        
	        try 
			{
	        	ContentElement content = getContentManager().extractContent(msg);
		        Concept action = ((Action)content).getAction();
         		
		        switch (msg.getPerformative()) 
		        {
		        case (ACLMessage.REQUEST):
			        if (action instanceof AddNewResult)
			        {
			        	content = getContentManager().extractContent(msg);
			            AddNewResult nr = (AddNewResult) ((Action)content).getAction();
			           
			            Result r = nr.getNewResult();
			            Stmt = C.createStatement();
						Stmt.executeUpdate("INSERT into UMCourtL.results(idresult, aid, res, code, action) VALUES ('"+System.currentTimeMillis()+"','"+msg.getSender().getName()+"','"+r.getRes()+"','"+r.getResultCode()+"','"+r.getAction()+"')");
			        }
		        	if (action instanceof AddNewTime)
		        	{
		        		content = getContentManager().extractContent(msg);
			            AddNewTime nt = (AddNewTime) ((Action)content).getAction();
			            
			            int time = nt.getTime();
			            String id = nt.getId();
			            
			            Stmt = C.createStatement();
			            if (id.equals("gci"))
			            	Stmt.executeUpdate("INSERT into UMCourtL.gcitimes(idgcitimes, time) VALUES ('"+msg.getConversationId()+"','"+time+"')");
			            if (id.equals("ps"))
			            	Stmt.executeUpdate("INSERT into UMCourtL.pstimes(pstimes, time) VALUES ('"+msg.getConversationId()+"','"+time+"')");
			            if (id.equals("nn"))
			            	Stmt.executeUpdate("INSERT into UMCourtL.nntimes(nntimes, time) VALUES ('"+msg.getConversationId()+"','"+time+"')");
			            if (id.equals("ut"))
			            	Stmt.executeUpdate("INSERT into UMCourtL.uttimes(uttimes, time) VALUES ('"+msg.getConversationId()+"','"+time+"')");
			            if (id.equals("cs"))
			            	Stmt.executeUpdate("INSERT into UMCourtL.cstimes(cstimes, time) VALUES ('"+msg.getConversationId()+"','"+time+"')");
		        	}
		        }
			}
	        catch(Exception e){e.printStackTrace();}
		}
	}
	
	private void printStats()
	{
		try 
		{
			//for each action studied print max time, min time, mean time, number of executions
			Statement select = C.createStatement();
			ResultSet result = select.executeQuery("SELECT * FROM umCourtl.gcitimes");
			long max = Long.MIN_VALUE;
			long min = Long.MAX_VALUE;
			int total = 0;
			int i=0;
			
			while (result.next())
			{
				long value = result.getLong(2);
				if (value < min)
					min = value;
				if (value > max)
					max = value;
				total += value;
				i++;
			}
			
			myprintln("Printing statistics of agent actions: (times in ms)");
			myprintln("get_complete_info");
			myprintln("\tIterations: "+i);
			myprintln("\tMax time: "+max);
			myprintln("\tMin time: "+min);
			myprintln("\tMean time: "+total/i);
			
			/*
			 * ***************************************************
			 * */
			select = C.createStatement();
			result = select.executeQuery("SELECT * FROM umCourtl.pstimes");
			max = Long.MIN_VALUE;
			min = Long.MAX_VALUE;
			total = 0;
			i=0;
			
			while (result.next())
			{
				long value = result.getLong(2);
				if (value < min)
					min = value;
				if (value > max)
					max = value;
				total += value;
				i++;
			}
			
			myprintln("pre_select");
			myprintln("\tIterations: "+i);
			myprintln("\tMax time: "+max);
			myprintln("\tMin time: "+min);
			myprintln("\tMean time: "+total/i);
			
			/*
			 * ***************************************************
			 * */
			select = C.createStatement();
			result = select.executeQuery("SELECT * FROM umCourtl.nntimes");
			max = Long.MIN_VALUE;
			min = Long.MAX_VALUE;
			total = 0;
			i=0;
			
			while (result.next())
			{
				long value = result.getLong(2);
				if (value < min)
					min = value;
				if (value > max)
					max = value;
				total += value;
				i++;
			}
			
			myprintln("nearest_neighbour");
			myprintln("\tIterations: "+i);
			myprintln("\tMax time: "+max);
			myprintln("\tMin time: "+min);
			myprintln("\tMean time: "+total/i);
			
			/*
			 * ***************************************************
			 * */
			select = C.createStatement();
			result = select.executeQuery("SELECT * FROM umCourtl.uttimes");
			max = Long.MIN_VALUE;
			min = Long.MAX_VALUE;
			total = 0;
			i=0;
			
			while (result.next())
			{
				long value = result.getLong(2);
				if (value < min)
					min = value;
				if (value > max)
					max = value;
				total += value;
				i++;
			}
			
			myprintln("utility");
			myprintln("\tIterations: "+i);
			myprintln("\tMax time: "+max);
			myprintln("\tMin time: "+min);
			myprintln("\tMean time: "+total/i);
			
			//percentage of success VS failure
			select = C.createStatement();
			result = select.executeQuery("SELECT COUNT(*) FROM umCourtl.casebase");
			result.next();
			myprintln("Indexed cases in the database: "+result.getInt(1));
			
			select = C.createStatement();
			result = select.executeQuery("SELECT COUNT(*) FROM umCourtl.results WHERE res = '"+UMCourtLVocabulary.SUCCESS+"'");
			result.next();
			int success = result.getInt(1);
			
			result = select.executeQuery("SELECT COUNT(*) FROM umCourtl.results WHERE res = '"+UMCourtLVocabulary.FAILURE+"' AND action = '"+UMCourtLVocabulary.PRE_SELECT+"'");
			result.next();
			int failure = result.getInt(1);
			
			total = success+failure;
			myprintln("Evaluation of System Performance: ");
			myprintln("Action: "+UMCourtLVocabulary.PRE_SELECT);
			myprintln("Successfull iterations: "+(success*100/total)+"% ("+success+")");
			myprintln("Failed iterations: "+(failure*100/total)+"% ("+failure+")");
			
			//Select top reasons for failure
			myprintln("Top reasons for failure");
			i = 0;
			ArrayList possibleSolutions = new ArrayList();
			result = select.executeQuery("SELECT code, COUNT(code) FROM umCourtl.results WHERE res = '"+UMCourtLVocabulary.FAILURE+"' AND action = '"+UMCourtLVocabulary.PRE_SELECT+"' GROUP BY code ORDER BY COUNT(code) DESC");
			while(result.next() && i < 3)
			{
				i++;
				int code = result.getInt(1);
				int number = result.getInt(2);
				//get error code description
				Statement select2 = C.createStatement();
				ResultSet result2 = select2.executeQuery("SELECT descr FROM umCourtl.resultdesc WHERE result = '"+code+"'");
				result2.next();
				String desc = result2.getString(1);
				myprintln("Code: "+code+"; Description: "+desc+" ; "+(number*100/total)+"% ("+number+")");
				
				//Get possible solutions for this error code
				result2 = select2.executeQuery("SELECT solution FROM umCourtl.solutions WHERE result = '"+code+"'");
				while (result2.next())
				{
					//Get the description of the solution code
					String solutionCode = result2.getString(1);
					Statement select3 = C.createStatement();
					ResultSet result3 = select3.executeQuery("SELECT descr FROM umCourtL.solutionsdesc WHERE solution = '"+solutionCode+"'");
					result3.next();
					String solutionDesc = result3.getString(1);
					possibleSolutions.add(solutionDesc);
				}
			}
			
			//Determine importance of solutions
			myprintln("Recommended actions: ");
			HashMap countSolutions = new HashMap();
			for (int j=0;j<possibleSolutions.size(); j++)
			{
				String solution = (String) possibleSolutions.get(j);
				if (countSolutions.containsKey(solution))
				{
					int count = (Integer) countSolutions.get(solution);
					count++;
					countSolutions.remove(solution);
					countSolutions.put(solution, count);
				}
				else countSolutions.put(solution, 1);
			}
			Iterator it = countSolutions.keySet().iterator();
			while (it.hasNext())
			{
				String solution = (String) it.next();
				int count = (Integer) countSolutions.get(solution);
				myprintln(solution+" ("+(count*100/possibleSolutions.size())+"%)");
			}
		} 
		catch (SQLException e) {e.printStackTrace();}
	}
	
}
